package javaidiot;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;


import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class Window extends JFrame {

    // Jx params
    private JTextArea m_AlertField = new JTextArea(2, 50);
    private JList m_ResultList = new JList();
    private JButton button1 = new JButton();
    // Options
    private String[] m_LabelArray = {"Products", "Employees", "Orders"};
    private int m_LabelCurrent = 0;
    // Lists' paramenters
    private ListData m_List = new ListData();
    private JPanel resultPanel = new JPanel();
    // MVC paramenters
    protected SQLConnection db;
    protected View view;
    protected Model model;

    public Window(SQLConnection d) {
        /*
         * Set MVC
         */
        db = d;
        view = new View();
        model = new Model(db);

        /*
         * Set GUI
         */
        // exit app when the window is closed
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // create UI panels, left to right layout
        JPanel buttonPanel = new JPanel(new FlowLayout());
        JPanel labelPanel = new JPanel(new FlowLayout());
        //JPanel resultPanel = new JPanel();
        resultPanel.setLayout(
                new BoxLayout(resultPanel, BoxLayout.PAGE_AXIS));
        m_AlertField.setEditable(false);
        resultPanel.add(
                new JLabel("Info:"));
        resultPanel.add(
                new JScrollPane(m_AlertField));
        resultPanel.add(
                new JLabel("Items"));
        resultPanel.add(
                new JScrollPane(m_ResultList));

        /*
         * Create Option Buttons and listeners
         * 
         */
        labelPanel.add(
                new JButton(new AbstractAction(m_LabelArray[0]) {

            @Override
            public void actionPerformed(ActionEvent e) {
                setLabel(0);
            }
        }));
        labelPanel.add(
                new JButton(new AbstractAction(m_LabelArray[1]) {

            @Override
            public void actionPerformed(ActionEvent e) {
                setLabel(1);
            }
        }));
        labelPanel.add(
                new JButton(new AbstractAction(m_LabelArray[2]) {

            @Override
            public void actionPerformed(ActionEvent e) {
                setLabel(2);
            }
        }));

        /*
         * Create list
         */
        model.selectProductList();
        m_List.setValues(view.getProductListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
        m_ResultList.setModel(m_List);

        /*
         * create buttons and listeners
         * Add
         * This button is accessible within the class to allow changes of its name
         */
        buttonPanel.add(button1);
        button1.addActionListener(new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonAdd();
            }
        });
        button1.setText("Add");

        /*
         * create buttons and listeners
         * Edit
         */
        buttonPanel.add(
                new JButton(new AbstractAction("Edit") {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonEdit();
            }
        }));

        /*
         * create buttons and listeners
         * Delete
         */
        buttonPanel.add(
                new JButton(new AbstractAction("Delete") {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonDelete();
            }
        }));

        /*
         * create buttons and listeners
         * Search
         */
        buttonPanel.add(
                new JButton(new AbstractAction("Search") {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonSearch();
            }
        }));

        /*
         * create buttons and listeners
         * Exit
         * 
         */
        buttonPanel.add(
                new JButton(new AbstractAction("Exit") {

            @Override
            public void actionPerformed(ActionEvent e) {
                buttonClose();
                System.exit(0);
            }
        }));

        /*
         * put the panels on window
         * 
         */
        Container panel = getContentPane();
        panel.setLayout(
                new BorderLayout());
        panel.add(labelPanel, BorderLayout.NORTH);
        panel.add(resultPanel, BorderLayout.CENTER);
        panel.add(buttonPanel, BorderLayout.SOUTH);
    }

    private void setLabel(int n) {
        m_LabelCurrent = n;
        m_AlertField.setText(m_LabelArray[m_LabelCurrent]);
        // Employees
        if (m_LabelCurrent == 1) {
            // Update GUI
            model.selectEmployeeList();
            m_List.setValues(view.getEmployeeListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
            button1.setText("Add");
            m_ResultList.updateUI();
        } // Orders
        else if (m_LabelCurrent == 2) {
            // Update GUI
            model.selectOrderList();
            m_List.setValues(view.getOrderListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
            button1.setText("View");
            m_ResultList.updateUI();
        } // Products
        else {
            // Update GUI
            model.selectProductList();
            m_List.setValues(view.getProductListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
            button1.setText("Add");
            m_ResultList.updateUI();
        }
    }

    private void buttonClose() {
        db.close();
    }

    /*
     * Set of actions for all GUI elements
     * 
     */
    private void buttonAdd() {
        // Employees
        if (m_LabelCurrent == 1) {
            b_employeeAdd();
        } // Orders
        else if (m_LabelCurrent == 2) {
            b_orderAdd();
        } // Products
        else {
            b_productAdd();
        }
    }

    private void buttonEdit() {
        // Employees
        if (m_LabelCurrent == 1) {
            b_employeeEdit();
        } // Orders
        else if (m_LabelCurrent == 2) {
            b_orderEdit();
        } // Products
        else {
            b_productEdit();
        }
    }

    private void buttonDelete() {
        // Employees
        if (m_LabelCurrent == 1) {
            b_employeeDelete();
        } // Orders
        else if (m_LabelCurrent == 2) {
            b_orderDelete();
        } // Products
        else {
            b_productDelete();
        }
    }

    private void buttonSearch() {
        // Employees
        if (m_LabelCurrent == 1) {
            b_employeeSearch();
        } // Orders
        else if (m_LabelCurrent == 2) {
            b_orderSearch();
        } // Products
        else {
            b_productSearch();
        }
    }

    private void b_productAdd() {
        // Input name
        String productName = JOptionPane.showInputDialog("Enter name");
        // Name is given
        if (productName != null && productName.length() > 0) {
            // Input price
            String productPrice = JOptionPane.showInputDialog(null, "Enter price", "0");
            m_AlertField.setText("");
            // Price is given
            if (productPrice != null) {
                if (Float.valueOf(productPrice) > 0f) {
                    model.addProduct(productName, productPrice);
                } else {
                    model.addProduct(productName);
                }
            }
            m_AlertField.setText("You have added item with id " + view.printArray(db.select.resultArray));
            // Nothing was entered. Notify
        } else {
            m_AlertField.setText(view.error("empty field"));
        }
        model.selectProductList();
        m_List.setValues(view.getProductListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
        m_ResultList.updateUI();
    }

    private void b_productDelete() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            String oldId = m_List.ids[index];
            model.selectProductById(oldId);
            String[][] array = db.select.resultArray;
            // Confirm
            int n = JOptionPane.showConfirmDialog(
                    null,
                    "Would you like to delete an item " + array[0][1] + "?",
                    "Confirm deletion, id " + oldId,
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE);
            if (n == 0) {
                // Delete
                model.deleteProduct(oldId);
                // Update GUI
                model.selectProductList();
                m_List.setValues(view.getProductListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
                m_ResultList.updateUI();
            }
        } else {
            m_AlertField.setText("No items selected");
        }
    }

    private void b_productEdit() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            String oldId = m_List.ids[index];
            model.selectProductById(oldId);
            String[][] array = db.select.resultArray;
            // Set name
            String productName = (String) JOptionPane.showInputDialog(
                    null,
                    "Enter new name",
                    array[0][1]);
            // If name was set
            if (productName != null) {
                // Set price
                String productPrice = (String) JOptionPane.showInputDialog(
                        null,
                        "Enter new price",
                        array[0][3]);
                // If price was set
                if (productPrice != null) {
                    // Confirm
                    int n = JOptionPane.showConfirmDialog(
                            null,
                            "Would you like to change item\n"
                            + array[0][1]
                            + ", "
                            + array[0][3]
                            + "\nto "
                            + productName
                            + ", "
                            + productPrice
                            + "?",
                            "Confirm update",
                            JOptionPane.YES_NO_OPTION,
                            JOptionPane.WARNING_MESSAGE);
                    // If confirmed
                    if (n == 0) {
                        // Update DB
                        model.updateProduct(oldId, productName, productPrice);
                        // Update GUI
                        model.selectProductList();
                        m_List.setValues(view.getProductListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
                        m_ResultList.updateUI();
                    }
                }
            }
        } else {
            m_AlertField.setText("No items selected");
        }
    }

    private void b_productSearch() {
        // Set name
        String name = (String) JOptionPane.showInputDialog(
                "Enter a part of name");
        if (name != null) {
            model.selectProductByName(name);
            // Update GUI
            m_List.setValues(view.getProductListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
            m_ResultList.updateUI();
        }
    }

    private void b_employeeAdd() {
        // Input name
        String name = JOptionPane.showInputDialog("Enter name");
        // Name is given
        if (name != null && name.length() > 0) {
            // Input price
            String phone = JOptionPane.showInputDialog(null, "Enter phone number", "");
            m_AlertField.setText("");
            // Price is given
            if (phone != null) {
                if (!phone.isEmpty()) {
                    model.addEmployee(name, phone);
                } else {
                    model.addEmployee(name);
                }
            }
            m_AlertField.setText("You have added employee with id " + view.printArray(db.select.resultArray));
            // Nothing was entered. Notify
        } else {
            m_AlertField.setText(view.error("empty field"));
        }
        model.selectEmployeeList();
        m_List.setValues(view.getEmployeeListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
        m_ResultList.updateUI();
    }

    private void b_employeeDelete() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            String oldId = m_List.ids[index];
            model.selectEmployeeById(oldId);
            String[][] array = db.select.resultArray;
            // Confirm
            int n = JOptionPane.showConfirmDialog(
                    null,
                    "Would you like to delete an employee " + array[0][1] + "?",
                    "Confirm deletion, id = " + oldId,
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE);
            if (n == 0) {
                // Delete
                model.deleteEmployee(oldId);
                // Update GUI
                model.selectEmployeeList();
                m_List.setValues(view.getEmployeeListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
                m_ResultList.updateUI();
            }
        } else {
            m_AlertField.setText("No employees selected");
        }
    }

    private void b_employeeEdit() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            String oldId = m_List.ids[index];
            model.selectEmployeeById(oldId);
            String[][] array = db.select.resultArray;
            // Set name
            String name = (String) JOptionPane.showInputDialog(
                    null,
                    "Enter new name",
                    array[0][1]);
            // If name was set
            if (name != null) {
                // Set price
                String phone = (String) JOptionPane.showInputDialog(
                        null,
                        "Enter new phone number",
                        array[0][2]);
                // If price was set
                if (phone != null) {
                    // Confirm
                    int n = JOptionPane.showConfirmDialog(
                            null,
                            "Would you like to change employee\n"
                            + array[0][1]
                            + ", "
                            + array[0][2]
                            + "\nto "
                            + name
                            + ", "
                            + phone
                            + "?",
                            "Confirm update",
                            JOptionPane.YES_NO_OPTION,
                            JOptionPane.WARNING_MESSAGE);
                    // If confirmed
                    if (n == 0) {
                        // Update DB
                        model.updateEmployee(oldId, name, phone);
                        // Update GUI
                        model.selectEmployeeList();
                        m_List.setValues(view.getEmployeeListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
                        m_ResultList.updateUI();
                    }
                }
            }
        } else {
            m_AlertField.setText("Noone is selected");
        }
    }

    private void b_employeeSearch() {
        // Set name
        String name = (String) JOptionPane.showInputDialog(
                "Enter a part of name");
        if (name != null) {
            model.selectEmployeeByName(name);
            // Update GUI
            m_List.setValues(view.getEmployeeListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
            m_ResultList.updateUI();
        }
    }

    private void b_orderAdd() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            model.selectOrderDetailsFull(m_List.ids[index]);
            // Show
            String orderDetails = view.getOrderInfo(db.select.resultArray);
            //custom title, no icon
            JOptionPane.showMessageDialog(
                    null,
                    orderDetails,
                    "Order details",
                    JOptionPane.PLAIN_MESSAGE);
        } else {
            m_AlertField.setText("No items selected");
        }
    }

    private void b_orderEdit() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            String orderId = m_List.ids[index];
            model.selectOrderById(orderId);
            String[][] array = db.select.resultArray;

            // Ha-ha, here comes a difference!
            // Generate editable options
            // Custom button text
            Object[] options = {
                "Change quantity",
                "Remove product",
                "Add product",
                "Assign employee",
                "Cancel"};
            int n = JOptionPane.showOptionDialog(
                    null,
                    "Choose search method:",
                    "Search orders",
                    JOptionPane.YES_NO_CANCEL_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null,
                    options,
                    options[0]);
            boolean cont = true;
            switch (n) {
                case 0:
                    // Add button edit or delete product with list of products in order
                    model.selectOrderDetails(orderId);
                    String[][] orderChangeDetails = db.select.resultArray;
                    String orderChangeStatement = "Order at "
                            + view.dateNicer(array[0][1])
                            + view.getOrderProducts(orderChangeDetails);
                    String[] orderChangeOptions = view.getNameArray(orderChangeDetails, 1);

                    String orderChangeString = (String) JOptionPane.showInputDialog(
                            null,
                            orderChangeStatement,
                            "Order. Set product",
                            JOptionPane.PLAIN_MESSAGE,
                            null,
                            orderChangeOptions,
                            orderChangeOptions[0]);
                    if (orderChangeString != null && orderChangeString.length() > 0) {
                        String orderChangeOldAmount = "";
                        String orderChangeProductId = "";

                        for (int i = 0; cont && i < orderChangeDetails.length; i++) {
                            if (orderChangeString.equalsIgnoreCase(orderChangeDetails[i][1])) {
                                orderChangeOldAmount = orderChangeDetails[i][2];
                                orderChangeProductId = orderChangeDetails[i][0];
                                cont = false;
                            }
                        }
                        String orderChangeNewAmount = (String) JOptionPane.showInputDialog(
                                null,
                                "Enter amount",
                                "Order. Change amount for " + orderChangeString,
                                JOptionPane.PLAIN_MESSAGE,
                                null,
                                null,
                                orderChangeOldAmount);
                        if (orderChangeNewAmount != null) {
                            model.updateOrderProductAmount(orderId, orderChangeProductId, orderChangeNewAmount);
                        }
                    }
                    break;
                case 1:
                    // Add button edit or delete product with list of products in order
                    model.selectOrderDetails(orderId);
                    String[][] orderDeleteDetails = db.select.resultArray;
                    String orderDeleteStatement = "Order at "
                            + view.dateNicer(array[0][1])
                            + view.getOrderProducts(orderDeleteDetails);
                    String[] orderDeleteOptions = view.getNameArray(orderDeleteDetails, 1);

                    String orderDeleteString = (String) JOptionPane.showInputDialog(
                            null,
                            orderDeleteStatement,
                            "Order. Remove product",
                            JOptionPane.PLAIN_MESSAGE,
                            null,
                            orderDeleteOptions,
                            orderDeleteOptions[0]);
                    if (orderDeleteString != null && orderDeleteString.length() > 0) {
                        // Confirm
                        int orderDeleteConfirm = JOptionPane.showConfirmDialog(
                                null,
                                "Would you like to delete an product " + orderDeleteString + "?",
                                "Confirm deletion of " + orderDeleteString,
                                JOptionPane.YES_NO_OPTION,
                                JOptionPane.WARNING_MESSAGE);
                        if (n == 1) {
                            String orderDeleteProductId = "";
                            for (int i = 0; cont && i < orderDeleteDetails.length; i++) {
                                if (orderDeleteString.equalsIgnoreCase(orderDeleteDetails[i][1])) {
                                    orderDeleteProductId = orderDeleteDetails[i][0];
                                    cont = false;
                                }
                            }
                            System.out.print(orderDeleteProductId);
                            model.updateOrderProductRemove(orderId, orderDeleteProductId);
                        }
                    }
                    break;
                case 2:
                    // Add field to append a new product to the order
                    model.selectOrderDetails(orderId);
                    String[][] orderAppendDetails = db.select.resultArray;
                    String orderAppendStatement = "Order at "
                            + view.dateNicer(array[0][1])
                            + view.getOrderProducts(orderAppendDetails);
                    model.selectOrderAdditionalProductList(orderId);
                    String[][] orderAppendProducts = db.select.resultArray;
                    String[] orderAppendOptions = view.getNameArray(orderAppendProducts, 1);
                    String orderAppendString = (String) JOptionPane.showInputDialog(
                            null,
                            orderAppendStatement,
                            "Order. Add product",
                            JOptionPane.PLAIN_MESSAGE,
                            null,
                            orderAppendOptions,
                            orderAppendOptions[0]);
                    if (orderAppendString != null && orderAppendString.length() > 0) {
                        String orderAppendProductId = "";
                        for (int i = 0; cont && i < orderAppendProducts.length; i++) {
                            if (orderAppendString.equalsIgnoreCase(orderAppendProducts[i][1])) {
                                orderAppendProductId = orderAppendProducts[i][0];
                                cont = false;
                            }
                        }
                        model.updateOrderProductAppend(orderId, orderAppendProductId);
                    }
                    break;
                case 3:
                    // Add field to append a new employee to order
                    model.selectOrderDetails(orderId);
                    String[][] orderEmpeeDetails = db.select.resultArray;
                    String orderEmpeeStatement = "Order at "
                            + view.dateNicer(array[0][1])
                            + view.getOrderProducts(orderEmpeeDetails);
                    model.selectEmployeeList();
                    String[][] orderEmpees = db.select.resultArray;
                    String[] orderEmpeeOptions = view.getNameArray(orderEmpees, 1);
                    String orderEmpeeString = (String) JOptionPane.showInputDialog(
                            null,
                            orderEmpeeStatement,
                            "Order. Add employee",
                            JOptionPane.PLAIN_MESSAGE,
                            null,
                            orderEmpeeOptions,
                            orderEmpeeOptions[0]);
                    if (orderEmpeeString != null && orderEmpeeString.length() > 0) {
                        String orderEmpeeId = "";
                        for (int i = 0; cont && i < orderEmpees.length; i++) {
                            if (orderEmpeeString.equalsIgnoreCase(orderEmpees[i][1])) {
                                orderEmpeeId = orderEmpees[i][0];
                                cont = false;
                            }
                        }
                        model.updateOrderSetEmployee(orderId, orderEmpeeId);
                    }
                    break;
                default:
                    break;
            }
            // Update GUI
            model.selectOrderList();
            m_List.setValues(view.getEmployeeListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
            m_ResultList.updateUI();
            setLabel(2);

        } else {
            m_AlertField.setText("Noone is selected");
        }
    }

    private void b_orderDelete() {
        if (!m_ResultList.isSelectionEmpty()) {
            int index = m_ResultList.getSelectedIndex();
            String oldId = m_List.ids[index];
            model.selectOrderById(oldId);
            String[][] array = db.select.resultArray;
            // Confirm
            int n = JOptionPane.showConfirmDialog(
                    null,
                    "Would you like to delete an order at " + view.dateNicer(array[0][1]) + "?",
                    "Confirm deletion, id " + oldId,
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE);
            if (n == 0) {
                // Delete
                model.deleteOrder(oldId);
                // Update GUI
                model.selectOrderList();
                m_List.setValues(view.getOrderListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
                m_ResultList.updateUI();
            }
        } else {
            m_AlertField.setText("No items selected");
        }
    }

    private boolean isValidDate(String[] s) {
        boolean r = false;
        if (s.length == 3) {
            if (s[0].matches("^[0-9]{4}$") || s[0].equalsIgnoreCase("*")) {
                if (s[1].matches("^[0-9]{2}$") || s[1].equalsIgnoreCase("*")) {
                    if (s[2].matches("^[0-9]{2}$") || s[2].equalsIgnoreCase("*")) {
                        r = true;
                    }
                }
            }
        }
        return r;
    }

    private void b_orderSearch() {
        // Generate search options
        //Custom button text
        Object[] options = {
            "By date",
            "By employee name",
            "By product name",
            "Cancel"};
        int n = JOptionPane.showOptionDialog(
                null,
                "Choose search method:",
                "Search orders",
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null,
                options,
                options[0]);

        switch (n) {
            case 0:
                String message = "Enter date or period to search in.\n\n"
                        + "Format should be YYYY-MM-DD, and use * to select a range.\n"
                        + "For example,\n2011-*-* to find all order for year 2011;\n"
                        + "2011-10-* to find all order for October 2011..";
                String date = (String) JOptionPane.showInputDialog(
                        null,
                        message,
                        "Search by date",
                        JOptionPane.QUESTION_MESSAGE);
                String[] resultDate = date.split("-");
                if (isValidDate(resultDate)) {
                    model.selectOrderByDate(resultDate);
                }
                break;
            case 1:
                model.selectEmployeeList();
                options = view.getNameArray(db.select.resultArray, 1);
                String name = (String) JOptionPane.showInputDialog(
                        null,
                        "Choose employee name",
                        "Search by employee",
                        JOptionPane.QUESTION_MESSAGE,
                        null,
                        options,
                        options[0]);
                if (name != null) {
                    model.selectOrderByEmployee(name);
                } else {
                    model.selectOrderList();
                }
                break;
            case 2:
                String product = (String) JOptionPane.showInputDialog(
                        null,
                        "Type a part of product name",
                        "Search by product",
                        JOptionPane.QUESTION_MESSAGE);
                if (product != null && product.length() > 0) {
                    model.selectOrderByProduct(product);
                } else {
                    model.selectOrderList();
                }
                break;
            default:
                break;
        }
        // Update GUI
        m_List.setValues(view.getOrderListArray(db.select.resultArray), view.getIdsArray(db.select.resultArray));
        m_ResultList.updateUI();
    }
}

class ListData extends javax.swing.AbstractListModel {

    String[] strings;
    String[] ids;

    public ListData() {
        strings = null;
        ids = null;
    }

    public ListData(String[] s) {
        strings = s;
    }

    public void setValues(String[] s, String[] n) {
        strings = s;
        ids = n;
    }

    public int getSize() {
        return strings.length;
    }

    public Object getElementAt(int index) {
        return strings[index];
    }
}
